package com.quanyan.pay.api.wechat.service.impl;

import com.quanyan.common.utils.*;
import com.quanyan.pay.api.alipay.service.impl.AlipayAPIServiceImpl;
import com.quanyan.pay.api.wechat.service.WechatAPIService;
import com.quanyan.pay.api.wechat.vo.*;
import com.quanyan.pay.enums.WxRefundStatusEnum;
import com.quanyan.pay.enums.WxReturnCodeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created by Zheng.Ke
 * Date 2017/2/16.
 */
@Service("wechatAPIService")
public class WechatAPIServiceImpl implements WechatAPIService {
    private static Logger logger = LoggerFactory.getLogger(WechatAPIServiceImpl.class);

    @Override
    public WxOrderQueryRespVo orderQuery(WxOrderQueryReqVo vo) {
        String url = "https://api.mch.weixin.qq.com/pay/orderquery";
        String apiKey = vo.getApiKey();
        // 不参与签名
        vo.setApiKey(null);
        vo.setSign(null);

        String sign = SignatureUtils.getWxSign(vo, apiKey);
        vo.setSign(sign);
        String responseStr = HttpUtils.sendWebRequestByPostJsonStr(null, url, XmlUtils.toXmlStr(vo));
        WxOrderQueryRespVo respVo = null;
        if (StringUtil.isBlankOrNull(responseStr)) {
            respVo = new WxOrderQueryRespVo();
            respVo.setRet(false);
            return respVo;
        }
        respVo = XmlUtils.xmlStrToEntity(responseStr, WxOrderQueryRespVo.class);
        respVo.setRet(true);
        return respVo;
    }

    @Override
    public WxUnifiedOrderRespVo unifiedOrder(WxUnifiedOrderReqVo vo) {
        String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        String apiKey = vo.getApiKey();
        // 不参与签名
        vo.setApiKey(null);
        vo.setSign(null);

        String sign = SignatureUtils.getWxSign(vo, apiKey);
        vo.setSign(sign);
        String requestXmlStr = XmlUtils.toXmlStr(vo);
        String responseStr = HttpUtils.sendWebRequestByPostJsonStr(null, url, requestXmlStr);
        logger.info("访问微信接口【统一下单】。请求：{}，晌应：{}。", requestXmlStr, responseStr);
        WxUnifiedOrderRespVo respVo = null;
        if (StringUtil.isBlankOrNull(responseStr)) {
            respVo = new WxUnifiedOrderRespVo();
            respVo.setRet(false);
            return respVo;
        }
        respVo = XmlUtils.xmlStrToEntity(responseStr, WxUnifiedOrderRespVo.class);
        respVo.setRet(true);
        return respVo;
    }

    @Override
    public WxCloseOrderRespVo closeOrder(WxCloseOrderReqVo vo) {
        String url = "https://api.mch.weixin.qq.com/pay/closeorder";
        String apiKey = vo.getApiKey();
        // 不参与签名
        vo.setApiKey(null);
        vo.setSign(null);

        String sign = SignatureUtils.getWxSign(vo, apiKey);
        vo.setSign(sign);
        String responseStr = HttpUtils.sendWebRequestByPostJsonStr(null, url, XmlUtils.toXmlStr(vo));
        WxCloseOrderRespVo respVo = null;
        if (StringUtil.isBlankOrNull(responseStr)) {
            respVo = new WxCloseOrderRespVo();
            respVo.setRet(false);
            return respVo;
        }
        respVo = XmlUtils.xmlStrToEntity(responseStr, WxCloseOrderRespVo.class);
        respVo.setRet(true);
        return respVo;
    }

    @Override
    public WxRefundRespVo refund(WxRefundReqVo vo) {
        String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
        String apiKey = vo.getApiKey();
        byte[] certData = vo.getCertData();
        String certPasswd = vo.getCertPasswd();
        // 不参与签名
        vo.setApiKey(null);
        vo.setSign(null);
        vo.setCertData(null);
        vo.setCertPasswd(null);

        String sign = SignatureUtils.getWxSign(vo, apiKey);
        vo.setSign(sign);
        String requestXmlStr = XmlUtils.toXmlStr(vo);
        String responseStr = HttpUtils.sendWebRequest(url, HttpMethod.POST, null, requestXmlStr.getBytes(), "UTF-8", null, null, certData, certPasswd);
        logger.info("访问微信接口【申请退款】。请求：{}，晌应：{}。", requestXmlStr, responseStr);
        WxRefundRespVo respVo = null;
        if (StringUtil.isBlankOrNull(responseStr)) {
            respVo = new WxRefundRespVo();
            respVo.setRet(false);
            return respVo;
        }
        respVo = XmlUtils.xmlStrToEntity(responseStr, WxRefundRespVo.class);
        respVo.setRet(true);
        return respVo;
    }

    @Override
    public WxRefundQueryRespVo refundQuery(WxRefundQueryReqVo vo) {
        String url = "https://api.mch.weixin.qq.com/pay/refundquery";
        String apiKey = vo.getApiKey();
        // 不参与签名
        vo.setApiKey(null);
        vo.setSign(null);

        String sign = SignatureUtils.getWxSign(vo, apiKey);
        vo.setSign(sign);
        String responseStr = HttpUtils.sendWebRequestByPostJsonStr(null, url, XmlUtils.toXmlStr(vo));
        WxRefundQueryRespVo respVo = null;
        if (StringUtil.isBlankOrNull(responseStr)) {
            respVo = new WxRefundQueryRespVo();
            respVo.setRet(false);
            return respVo;
        }
        respVo = XmlUtils.xmlStrToEntity(responseStr, WxRefundQueryRespVo.class);
        // 设置refundInfoList
        Map<String, String> responseMap = XmlUtils.xmlStrToMap(responseStr);
        List<WxRefundInfoItem> refundInfoList = new ArrayList<>();
        if (WxReturnCodeEnum.SUCCESS == respVo.getReturn_code()) {
            int refundCount = respVo.getRefund_count();
            for (int i=0; i<refundCount; i++) {
                WxRefundInfoItem infoItem = new WxRefundInfoItem();
                String outRefundNo = responseMap.get("out_refund_no_" + i);
                String refundId = responseMap.get("refund_id_" + i);
                String refundChannel = responseMap.get("refund_channel_" + i);
                String refundAccount = responseMap.get("refund_account_" + i);
                String refundFeeStr = responseMap.get("refund_fee_" + i);
                String refundStatusStr = responseMap.get("refund_status_" + i);
                String refundRecvAccout = responseMap.get("refund_recv_accout_" + i);

                infoItem.setOut_refund_no(outRefundNo);
                infoItem.setRefund_id(refundId);
                infoItem.setRefund_fee(Integer.parseInt(refundFeeStr));
                infoItem.setRefund_channel(refundChannel);
                infoItem.setRefund_account(refundAccount);
                infoItem.setRefund_recv_accout(refundRecvAccout);
                infoItem.setRefund_status(WxRefundStatusEnum.valueOf(refundStatusStr));
                refundInfoList.add(infoItem);
            }
        }
        respVo.setRefundInfoList(refundInfoList);

        respVo.setRet(true);
        return respVo;
    }

    @Override
    public WxDownloadBillRespVo downloadBill(WxDownloadBillReqVo vo) {
        String url = "https://api.mch.weixin.qq.com/pay/downloadbill";
        String apiKey = vo.getApiKey();
        // 不参与签名
        vo.setApiKey(null);
        vo.setSign(null);

        String sign = SignatureUtils.getWxSign(vo, apiKey);
        vo.setSign(sign);
        String responseStr = HttpUtils.sendWebRequestByPostJsonStr(null, url, XmlUtils.toXmlStr(vo));
        WxDownloadBillRespVo respVo = null;
        if (StringUtil.isBlankOrNull(responseStr)) {
            respVo = new WxDownloadBillRespVo();
            respVo.setRet(false);
            return respVo;
        }
        if (responseStr.startsWith("<xml>")) { // 返回错误
            respVo = XmlUtils.xmlStrToEntity(responseStr, WxDownloadBillRespVo.class);
        } else { // 正确返回
            respVo = new WxDownloadBillRespVo();
            respVo.setReturn_code(WxReturnCodeEnum.SUCCESS);
            respVo.setReturn_msg("ok");
            String[] billData = responseStr.split("\\r\\n");
            List<String[]> data = new ArrayList<>();
            for (int i=0; i<billData.length; i++) {
                String billStr = billData[i];
                if (i == 0) { // 表头
                    String[] title = billStr.split(",");
                    respVo.setTitle(title);
                    continue;
                }
                if (billStr.contains("总交易单数")) {
                    break;
                }
                String[] d = billStr.replaceAll("`", "").split(",");
                data.add(d);
            }
            respVo.setData(data);
        }

        respVo.setRet(true);
        return respVo;
    }

    @Override
    public boolean verifySign(WxPayNotifyParamsVo vo, String apiKey) {
        if (vo == null) {
            return false;
        }
        String needVerifySign = vo.getSign();
        // sign不参与签名
        vo.setSign(null);
        String sign = SignatureUtils.getWxSign(vo, apiKey);
        if (!sign.equals(needVerifySign)) {
            return false;
        }
        return true;
    }

    @Override
    public WxMicroPayRespVo microPay(WxMicroPayReqVo vo) {
        String url = "https://api.mch.weixin.qq.com/pay/micropay";
        String apiKey = vo.getApiKey();
        // 不参与签名
        vo.setApiKey(null);
        vo.setSign(null);

        String sign = SignatureUtils.getWxSign(vo, apiKey);
        vo.setSign(sign);
        String requestXmlStr = XmlUtils.toXmlStr(vo);
        String responseStr = HttpUtils.sendWebRequestByPostJsonStr(null, url, requestXmlStr);
        logger.info("访问微信接口【提交刷卡支付API】。请求：{}，晌应：{}。", requestXmlStr, responseStr);
        WxMicroPayRespVo respVo = null;
        if (StringUtil.isBlankOrNull(responseStr)) {
            respVo = new WxMicroPayRespVo();
            respVo.setRet(false);
            return respVo;
        }
        respVo = XmlUtils.xmlStrToEntity(responseStr, WxMicroPayRespVo.class);

        respVo.setRet(true);
        return respVo;
    }

    @Override
    public WxReverseRespVo reverse(WxReverseReqVo vo) {
        String url = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
        String apiKey = vo.getApiKey();
        byte[] certData = vo.getCertData();
        String certPasswd = vo.getCertPasswd();
        // 不参与签名
        vo.setApiKey(null);
        vo.setSign(null);
        vo.setCertData(null);
        vo.setCertPasswd(null);

        String sign = SignatureUtils.getWxSign(vo, apiKey);
        vo.setSign(sign);
        String requestXmlStr = XmlUtils.toXmlStr(vo);
        String responseStr = HttpUtils.sendWebRequest(url, HttpMethod.POST, null, requestXmlStr.getBytes(), "UTF-8", null, null, certData, certPasswd);
        logger.info("访问微信接口【撤销订单API(刷卡支付)】。请求：{}，晌应：{}。", requestXmlStr, responseStr);
        WxReverseRespVo respVo = null;
        if (StringUtil.isBlankOrNull(responseStr)) {
            respVo = new WxReverseRespVo();
            respVo.setRet(false);
            return respVo;
        }
        respVo = XmlUtils.xmlStrToEntity(responseStr, WxReverseRespVo.class);

        respVo.setRet(true);
        return respVo;
    }

    @Override
    public WxAuthCodeToOpenIdRespVo authCodeToOpenId(WxAuthCodeToOpenIdReqVo vo) {
        String url = "https://api.mch.weixin.qq.com/tools/authcodetoopenid";
        String apiKey = vo.getApiKey();
        // 不参与签名
        vo.setApiKey(null);
        vo.setSign(null);

        String sign = SignatureUtils.getWxSign(vo, apiKey);
        vo.setSign(sign);
        String responseStr = HttpUtils.sendWebRequestByPostJsonStr(null, url, XmlUtils.toXmlStr(vo));
        WxAuthCodeToOpenIdRespVo respVo = null;
        if (StringUtil.isBlankOrNull(responseStr)) {
            respVo = new WxAuthCodeToOpenIdRespVo();
            respVo.setRet(false);
            return respVo;
        }
        respVo = XmlUtils.xmlStrToEntity(responseStr, WxAuthCodeToOpenIdRespVo.class);

        respVo.setRet(true);
        return respVo;
    }

    @Override
    public WxTransfersRespVo transfers(WxTransfersReqVo vo) {
        String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
        String apiKey = vo.getApiKey();
        byte[] certData = vo.getCertData();
        String certPasswd = vo.getCertPasswd();
        // 不参与签名
        vo.setApiKey(null);
        vo.setSign(null);
        vo.setCertData(null);
        vo.setCertPasswd(null);

        String sign = SignatureUtils.getWxSign(vo, apiKey);
        vo.setSign(sign);
        String requestXmlStr = XmlUtils.toXmlStr(vo);
        String responseStr = HttpUtils.sendWebRequest(url, HttpMethod.POST, null, requestXmlStr.getBytes(), "UTF-8", null, null, certData, certPasswd);
        logger.info("访问微信接口【企业付款API】。请求：{}，晌应：{}。", requestXmlStr, responseStr);
        WxTransfersRespVo respVo = null;
        if (StringUtil.isBlankOrNull(responseStr)) {
            respVo = new WxTransfersRespVo();
            respVo.setRet(false);
            return respVo;
        }
        respVo = XmlUtils.xmlStrToEntity(responseStr, WxTransfersRespVo.class);

        respVo.setRet(true);
        return respVo;
    }

    @Override
    public WxGetTransferInfoRespVo getTransferInfo(WxGetTransferInfoReqVo vo) {
        String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo";
        String apiKey = vo.getApiKey();
        byte[] certData = vo.getCertData();
        String certPasswd = vo.getCertPasswd();
        // 不参与签名
        vo.setApiKey(null);
        vo.setSign(null);
        vo.setCertData(null);
        vo.setCertPasswd(null);

        String sign = SignatureUtils.getWxSign(vo, apiKey);
        vo.setSign(sign);
        String responseStr = HttpUtils.sendWebRequest(url, HttpMethod.POST, null, XmlUtils.toXmlStr(vo).getBytes(), "UTF-8", null, null, certData, certPasswd);
        WxGetTransferInfoRespVo respVo = null;
        if (StringUtil.isBlankOrNull(responseStr)) {
            respVo = new WxGetTransferInfoRespVo();
            respVo.setRet(false);
            return respVo;
        }
        respVo = XmlUtils.xmlStrToEntity(responseStr, WxGetTransferInfoRespVo.class);

        respVo.setRet(true);
        return respVo;
    }

    @Override
    public WxOauthRespVo oauth(WxOauthReqVo vo) {
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=%s";
        url = String.format(url, vo.getAppid(), vo.getSecret(), vo.getCode(), vo.getGrant_type());

        String responseStr = HttpUtils.sendWebRequestByGet(null, url);

        WxOauthRespVo respVo = null;
        if (StringUtil.isBlankOrNull(responseStr)) {
            respVo = new WxOauthRespVo();
            respVo.setRet(false);
            return respVo;
        }

        respVo = GsonUtils.jsonStrToEntity(responseStr, WxOauthRespVo.class);

        respVo.setRet(true);
        return respVo;
    }
}
